#include "buffer_alloc.hpp"
#include "buffer.hpp"

namespace buffer
{
	Buffer::Buffer(int32_t size)
	{
		_start  = ((char*)this) + sizeof(*this);
		_end    = ((char*)this) + size;
		_rd_cur = _wr_cur = _start;

		_next = NULL;
	}

	int Buffer::put(const byte * first, const byte * last)
	{
		assert(last - first >= 0);
		
		int copy = MIN(_end - _wr_cur, last - first);
			
		memmove(_wr_cur, first, copy);

		_wr_cur += copy;

		return copy;
	}
	
	int Buffer::put(const Buffer & buffer)
	{
		return put(buffer._rd_cur, buffer._wr_cur);
	}
	
	int Buffer::get(byte * data, int32_t size)
	{
		int copy = MIN(_wr_cur - _rd_cur, size);
		
		memmove(data, _rd_cur, copy);

		_rd_cur += copy;
		
		return copy;
	}

	int Buffer::get(Buffer & buffer)
	{
		int copy = get(buffer._wr_cur, buffer._end - buffer._wr_cur);
		
		buffer._wr_cur += copy;

		return copy;
	}

	int Buffer::read(int fd, int nbytes)
	{
		if (nbytes < 0 || nbytes > (_end - _wr_cur))
		{
			nbytes = _end - _wr_cur;
		}

		int nread = ::read(fd, _wr_cur, nbytes);

		if (nread > 0)
		{
			_wr_cur += nread;
		}

		return (nread >= 0? nread: (errno > 0? -errno: nread));
	}

	int Buffer::put_skip(int offset)
	{
		if (offset > 0)
		{
			offset   = MIN(_end - _wr_cur, offset);
			_wr_cur += offset;
		}
		return offset;
	}

	int Buffer::get_skip(int offset)
	{
		if (offset > 0)
		{
			offset   = MIN(_wr_cur - _rd_cur, offset);
			_rd_cur += offset;
		}
		return offset;
	}

#if 0
	Buffer::Buffer(const byte * first, const byte * last, int32_t size)
	{
		if (NULL == first || NULL == last || last <= first)
		{
			new (this) Buffer(size);
			return;
		}

		assert((last - first) <= size);

		_start  = new byte[size];
		_end    = _start + size;
		_rd_cur = _start;
		_wr_cur = _start + (last - first);
		_next = NULL;
		
		memmove(_start, first, last - first);
	}

	Buffer::Buffer(const Buffer & buffer)
	{
		new (this) Buffer(buffer._start, buffer._wr_cur, buffer._end - buffer._start);
		
		_rd_cur = buffer._rd_cur;
		_wr_cur = buffer._wr_cur;
		_next   = NULL;
	}

	Buffer & Buffer::operator = (const Buffer & rhs)
	{
		if (this == &rhs)
		{
			return *this;
		}

		SAFE_DELETE_ARR(_start);
		new (this) Buffer(rhs);
		return *this;
	}

	Buffer::~Buffer()
	{
		SAFE_DELETE_ARR(_start);
		_end = _rd_cur = _wr_cur = 0;
		_next = NULL;
	}
#endif

};

